home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 22 / PCPP #22.iso / Quake2 / q2source_12_11 / utils3 / qe4 / brush.c next >
Encoding:
C/C++ Source or Header  |  1997-11-18  |  30.2 KB  |  1,547 lines

  1. #include <assert.h>
  2. #include "qe3.h"
  3.  
  4. #define MAX_POINTS_ON_WINDING    64
  5.  
  6. face_t *Face_Alloc( void );
  7. void    Face_Free( face_t *f );
  8.  
  9. winding_t    *NewWinding (int points);
  10. void        FreeWinding (winding_t *w);
  11. winding_t    *Winding_Clone( winding_t *w );
  12. winding_t    *ClipWinding (winding_t *in, plane_t *split, qboolean keepon);
  13.  
  14. void PrintWinding (winding_t *w)
  15. {
  16.     int        i;
  17.     
  18.     printf ("-------------\n");
  19.     for (i=0 ; i<w->numpoints ; i++)
  20.         printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
  21.         , w->points[i][1], w->points[i][2]);
  22. }
  23.  
  24. void PrintPlane (plane_t *p)
  25. {
  26.     printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n",  p->normal[0],  p->normal[1], 
  27.     p->normal[2],  p->dist);
  28. }
  29.  
  30. void PrintVector (vec3_t v)
  31. {
  32.      printf ("(%5.2f, %5.2f, %5.2f)\n",  v[0],  v[1], v[2]);
  33. }
  34.  
  35.  
  36. face_t    *Face_Clone (face_t *f)
  37. {
  38.     face_t    *n;
  39.  
  40.     n = Face_Alloc();
  41.     n->texdef = f->texdef;
  42.     memcpy (n->planepts, f->planepts, sizeof(n->planepts));
  43.  
  44.     // all other fields are derived, and will be set by Brush_Build
  45.     return n;
  46. }
  47.  
  48. //============================================================================
  49.  
  50. #define    BOGUS_RANGE    18000
  51.  
  52.  
  53. /*
  54. ==================
  55. NewWinding
  56. ==================
  57. */
  58. winding_t *NewWinding (int points)
  59. {
  60.     winding_t    *w;
  61.     int            size;
  62.     
  63.     if (points > MAX_POINTS_ON_WINDING)
  64.         Error ("NewWinding: %i points", points);
  65.     
  66.     size = (int)((winding_t *)0)->points[points];
  67.     w = malloc (size);
  68.     memset (w, 0, size);
  69.     w->maxpoints = points;
  70.     
  71.     return w;
  72. }
  73.  
  74.  
  75. void FreeWinding (winding_t *w)
  76. {
  77.     free (w);
  78. }
  79.  
  80.  
  81. /*
  82. ==================
  83. Winding_Clone
  84. ==================
  85. */
  86. winding_t *Winding_Clone(winding_t *w)
  87. {
  88.     int            size;
  89.     winding_t    *c;
  90.     
  91.     size = (int)((winding_t *)0)->points[w->numpoints];
  92.     c = qmalloc (size);
  93.     memcpy (c, w, size);
  94.     return c;
  95. }
  96.  
  97.  
  98. /*
  99. ==================
  100. ClipWinding
  101.  
  102. Clips the winding to the plane, returning the new winding on the positive side
  103. Frees the input winding.
  104. If keepon is true, an exactly on-plane winding will be saved, otherwise
  105. it will be clipped away.
  106. ==================
  107. */
  108. winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
  109. {
  110.     vec_t    dists[MAX_POINTS_ON_WINDING];
  111.     int        sides[MAX_POINTS_ON_WINDING];
  112.     int        counts[3];
  113.     vec_t    dot;
  114.     int        i, j;
  115.     vec_t    *p1, *p2;
  116.     vec3_t    mid;
  117.     winding_t    *neww;
  118.     int        maxpts;
  119.     
  120.     counts[0] = counts[1] = counts[2] = 0;
  121.  
  122. // determine sides for each point
  123.     for (i=0 ; i<in->numpoints ; i++)
  124.     {
  125.         dot = DotProduct (in->points[i], split->normal);
  126.         dot -= split->dist;
  127.         dists[i] = dot;
  128.         if (dot > ON_EPSILON)
  129.             sides[i] = SIDE_FRONT;
  130.         else if (dot < -ON_EPSILON)
  131.             sides[i] = SIDE_BACK;
  132.         else
  133.         {
  134.             sides[i] = SIDE_ON;
  135.         }
  136.         counts[sides[i]]++;
  137.     }
  138.     sides[i] = sides[0];
  139.     dists[i] = dists[0];
  140.     
  141.     if (keepon && !counts[0] && !counts[1])
  142.         return in;
  143.         
  144.     if (!counts[0])
  145.     {
  146.         FreeWinding (in);
  147.         return NULL;
  148.     }
  149.     if (!counts[1])
  150.         return in;
  151.     
  152.     maxpts = in->numpoints+4;    // can't use counts[0]+2 because
  153.                                 // of fp grouping errors
  154.     neww = NewWinding (maxpts);
  155.         
  156.     for (i=0 ; i<in->numpoints ; i++)
  157.     {
  158.         p1 = in->points[i];
  159.         
  160.         if (sides[i] == SIDE_ON)
  161.         {
  162.             VectorCopy (p1, neww->points[neww->numpoints]);
  163.             neww->numpoints++;
  164.             continue;
  165.         }
  166.     
  167.         if (sides[i] == SIDE_FRONT)
  168.         {
  169.             VectorCopy (p1, neww->points[neww->numpoints]);
  170.             neww->numpoints++;
  171.         }
  172.         
  173.         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  174.             continue;
  175.             
  176.     // generate a split point
  177.         p2 = in->points[(i+1)%in->numpoints];
  178.         
  179.         dot = dists[i] / (dists[i]-dists[i+1]);
  180.         for (j=0 ; j<3 ; j++)
  181.         {    // avoid round off error when possible
  182.             if (split->normal[j] == 1)
  183.                 mid[j] = split->dist;
  184.             else if (split->normal[j] == -1)
  185.                 mid[j] = -split->dist;
  186.             else
  187.                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  188.         }
  189.             
  190.         VectorCopy (mid, neww->points[neww->numpoints]);
  191.         neww->numpoints++;
  192.     }
  193.     
  194.     if (neww->numpoints > maxpts)
  195.         Error ("ClipWinding: points exceeded estimate");
  196.         
  197. // free the original winding
  198.     FreeWinding (in);
  199.     
  200.     return neww;
  201. }
  202.  
  203.  
  204.  
  205. /*
  206. =============================================================================
  207.  
  208.             TEXTURE COORDINATES
  209.  
  210. =============================================================================
  211. */
  212.  
  213.  
  214. /*
  215. ==================
  216. textureAxisFromPlane
  217. ==================
  218. */
  219. vec3_t    baseaxis[18] =
  220. {
  221. {0,0,1}, {1,0,0}, {0,-1,0},            // floor
  222. {0,0,-1}, {1,0,0}, {0,-1,0},        // ceiling
  223. {1,0,0}, {0,1,0}, {0,0,-1},            // west wall
  224. {-1,0,0}, {0,1,0}, {0,0,-1},        // east wall
  225. {0,1,0}, {1,0,0}, {0,0,-1},            // south wall
  226. {0,-1,0}, {1,0,0}, {0,0,-1}            // north wall
  227. };
  228.  
  229. void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
  230. {
  231.     int        bestaxis;
  232.     float    dot,best;
  233.     int        i;
  234.     
  235.     best = 0;
  236.     bestaxis = 0;
  237.     
  238.     for (i=0 ; i<6 ; i++)
  239.     {
  240.         dot = DotProduct (pln->normal, baseaxis[i*3]);
  241.         if (dot > best)
  242.         {
  243.             best = dot;
  244.             bestaxis = i;
  245.         }
  246.     }
  247.     
  248.     VectorCopy (baseaxis[bestaxis*3+1], xv);
  249.     VectorCopy (baseaxis[bestaxis*3+2], yv);
  250. }
  251.  
  252.  
  253. float    lightaxis[3] = {0.6, 0.8, 1.0};
  254. /*
  255. ================
  256. SetShadeForPlane
  257.  
  258. Light different planes differently to
  259. improve recognition
  260. ================
  261. */
  262. float SetShadeForPlane (plane_t *p)
  263. {
  264.     int        i;
  265.     float    f;
  266.  
  267.     // axial plane
  268.     for (i=0 ; i<3 ; i++)
  269.         if (fabs(p->normal[i]) > 0.9)
  270.         {
  271.             f = lightaxis[i];
  272.             return f;
  273.         }
  274.  
  275.     // between two axial planes
  276.     for (i=0 ; i<3 ; i++)
  277.         if (fabs(p->normal[i]) < 0.1)
  278.         {
  279.             f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
  280.             return f;
  281.         }
  282.  
  283.     // other
  284.     f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
  285.     return f;
  286. }
  287.  
  288. vec3_t  vecs[2];
  289. float    shift[2];
  290.  
  291. /*
  292. ================
  293. BeginTexturingFace
  294. ================
  295. */
  296. void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q)
  297. {
  298.     vec3_t    pvecs[2];
  299.     int        sv, tv;
  300.     float    ang, sinv, cosv;
  301.     float    ns, nt;
  302.     int        i,j;
  303.     float    shade;
  304.  
  305.     // get natural texture axis
  306.     TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
  307.  
  308.     // set shading for face
  309.     shade = SetShadeForPlane (&f->plane);
  310.     if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize)
  311.     {
  312.         f->d_color[0] = 
  313.         f->d_color[1] = 
  314.         f->d_color[2] = shade;
  315.     }
  316.     else
  317.     {
  318.         f->d_color[0] = shade*q->color[0];
  319.         f->d_color[1] = shade*q->color[1];
  320.         f->d_color[2] = shade*q->color[2];
  321.     }
  322.  
  323.     if (camera.draw_mode != cd_texture)
  324.         return;
  325.  
  326.     if (!f->texdef.scale[0])
  327.         f->texdef.scale[0] = 1;
  328.     if (!f->texdef.scale[1])
  329.         f->texdef.scale[1] = 1;
  330.  
  331.  
  332. // rotate axis
  333.     if (f->texdef.rotate == 0)
  334.         { sinv = 0 ; cosv = 1; }
  335.     else if (f->texdef.rotate == 90)
  336.         { sinv = 1 ; cosv = 0; }
  337.     else if (f->texdef.rotate == 180)
  338.         { sinv = 0 ; cosv = -1; }
  339.     else if (f->texdef.rotate == 270)
  340.         { sinv = -1 ; cosv = 0; }
  341.     else
  342.     {    
  343.         ang = f->texdef.rotate / 180 * Q_PI;
  344.         sinv = sin(ang);
  345.         cosv = cos(ang);
  346.     }
  347.  
  348.     if (pvecs[0][0])
  349.         sv = 0;
  350.     else if (pvecs[0][1])
  351.         sv = 1;
  352.     else
  353.         sv = 2;
  354.                 
  355.     if (pvecs[1][0])
  356.         tv = 0;
  357.     else if (pvecs[1][1])
  358.         tv = 1;
  359.     else
  360.         tv = 2;
  361.                     
  362.     for (i=0 ; i<2 ; i++)
  363.     {
  364.         ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
  365.         nt = sinv * pvecs[i][sv] +  cosv * pvecs[i][tv];
  366.         vecs[i][sv] = ns;
  367.         vecs[i][tv] = nt;
  368.     }
  369.  
  370.     for (i=0 ; i<2 ; i++)
  371.         for (j=0 ; j<3 ; j++)
  372.             vecs[i][j] = vecs[i][j] / f->texdef.scale[i];
  373. }
  374.  
  375.  
  376. void _EmitTextureCoordinates (vec3_t v, qtexture_t *q)
  377. {
  378.     float    s, t;
  379.  
  380.     s = DotProduct (v, vecs[0]);
  381.     t = DotProduct (v, vecs[1]);
  382.     
  383.     s += shift[0];
  384.     t += shift[1];
  385.     
  386.     s /= q->width;
  387.     t /= q->height;
  388.  
  389.     glTexCoord2f (s, t);
  390. }
  391.  
  392. void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
  393. {
  394.     float    s, t, ns, nt;
  395.     float    ang, sinv, cosv;
  396.     vec3_t    vecs[2];
  397.     texdef_t    *td;
  398.  
  399.     // get natural texture axis
  400.     TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
  401.  
  402.     td = &f->texdef;
  403.  
  404.     ang = td->rotate / 180 * Q_PI;
  405.     sinv = sin(ang);
  406.     cosv = cos(ang);
  407.     
  408.     if (!td->scale[0])
  409.         td->scale[0] = 1;
  410.     if (!td->scale[1])
  411.         td->scale[1] = 1;
  412.  
  413.     s = DotProduct(xyzst, vecs[0]);
  414.     t = DotProduct(xyzst, vecs[1]);
  415.  
  416.     ns = cosv * s - sinv * t;
  417.     nt = sinv * s +  cosv * t;
  418.  
  419.     s = ns/td->scale[0] + td->shift[0];
  420.     t = nt/td->scale[1] + td->shift[1];
  421.  
  422.     // gl scales everything from 0 to 1
  423.     s /= q->width;
  424.     t /= q->height;
  425.  
  426.     xyzst[3] = s;
  427.     xyzst[4] = t;
  428. }
  429.  
  430. //==========================================================================
  431.  
  432.  
  433. /*
  434. =================
  435. BasePolyForPlane
  436. =================
  437. */
  438. winding_t *BasePolyForPlane (plane_t *p)
  439. {
  440.     int        i, x;
  441.     vec_t    max, v;
  442.     vec3_t    org, vright, vup;
  443.     winding_t    *w;
  444.     
  445. // find the major axis
  446.  
  447.     max = -BOGUS_RANGE;
  448.     x = -1;
  449.     for (i=0 ; i<3; i++)
  450.     {
  451.         v = fabs(p->normal[i]);
  452.         if (v > max)
  453.         {
  454.             x = i;
  455.             max = v;
  456.         }
  457.     }
  458.     if (x==-1)
  459.         Error ("BasePolyForPlane: no axis found");
  460.         
  461.     VectorCopy (vec3_origin, vup);    
  462.     switch (x)
  463.     {
  464.     case 0:
  465.     case 1:
  466.         vup[2] = 1;
  467.         break;        
  468.     case 2:
  469.         vup[0] = 1;
  470.         break;        
  471.     }
  472.  
  473.  
  474.     v = DotProduct (vup, p->normal);
  475.     VectorMA (vup, -v, p->normal, vup);
  476.     VectorNormalize (vup);
  477.         
  478.     VectorScale (p->normal, p->dist, org);
  479.     
  480.     CrossProduct (vup, p->normal, vright);
  481.     
  482.     VectorScale (vup, 8192, vup);
  483.     VectorScale (vright, 8192, vright);
  484.  
  485. // project a really big    axis aligned box onto the plane
  486.     w = NewWinding (4);
  487.     
  488.     VectorSubtract (org, vright, w->points[0]);
  489.     VectorAdd (w->points[0], vup, w->points[0]);
  490.     
  491.     VectorAdd (org, vright, w->points[1]);
  492.     VectorAdd (w->points[1], vup, w->points[1]);
  493.     
  494.     VectorAdd (org, vright, w->points[2]);
  495.     VectorSubtract (w->points[2], vup, w->points[2]);
  496.     
  497.     VectorSubtract (org, vright, w->points[3]);
  498.     VectorSubtract (w->points[3], vup, w->points[3]);
  499.     
  500.     w->numpoints = 4;
  501.     
  502.     return w;    
  503. }
  504.  
  505. void Brush_MakeFacePlanes (brush_t *b)
  506. {
  507.     face_t    *f;
  508.     int        j;
  509.     vec3_t    t1, t2, t3;
  510.  
  511.     for (f=b->brush_faces ; f ; f=f->next)
  512.     {
  513.     // convert to a vector / dist plane
  514.         for (j=0 ; j<3 ; j++)
  515.         {
  516.             t1[j] = f->planepts[0][j] - f->planepts[1][j];
  517.             t2[j] = f->planepts[2][j] - f->planepts[1][j];
  518.             t3[j] = f->planepts[1][j];
  519.         }
  520.         
  521.         CrossProduct(t1,t2, f->plane.normal);
  522.         if (VectorCompare (f->plane.normal, vec3_origin))
  523.             printf ("WARNING: brush plane with no normal\n");
  524.         VectorNormalize (f->plane.normal);
  525.         f->plane.dist = DotProduct (t3, f->plane.normal);
  526.     }
  527. }
  528.  
  529. void DrawBrushEntityName (brush_t *b)
  530. {
  531.     char    *name;
  532.     float    a, s, c;
  533.     vec3_t    mid;
  534.     int        i;
  535.  
  536.     if (!b->owner)
  537.         return;        // during contruction
  538.  
  539.     if (b->owner == world_entity)
  540.         return;
  541.  
  542.     if (b != b->owner->brushes.onext)
  543.         return;    // not key brush
  544.  
  545.     // draw the angle pointer
  546.     a = FloatForKey (b->owner, "angle");
  547.     if (a)
  548.     {
  549.         s = sin (a/180*Q_PI);
  550.         c = cos (a/180*Q_PI);
  551.         for (i=0 ; i<3 ; i++)
  552.             mid[i] = (b->mins[i] + b->maxs[i])*0.5; 
  553.  
  554.         glBegin (GL_LINE_STRIP);
  555.         glVertex3fv (mid);
  556.         mid[0] += c*8;
  557.         mid[1] += s*8;
  558.         glVertex3fv (mid);
  559.         mid[0] -= c*4;
  560.         mid[1] -= s*4;
  561.         mid[0] -= s*4;
  562.         mid[1] += c*4;
  563.         glVertex3fv (mid);
  564.         mid[0] += c*4;
  565.         mid[1] += s*4;
  566.         mid[0] += s*4;
  567.         mid[1] -= c*4;
  568.         glVertex3fv (mid);
  569.         mid[0] -= c*4;
  570.         mid[1] -= s*4;
  571.         mid[0] += s*4;
  572.         mid[1] -= c*4;
  573.         glVertex3fv (mid);
  574.         glEnd ();
  575.     }
  576.  
  577.     if (!g_qeglobals.d_savedinfo.show_names)
  578.         return;
  579.  
  580.     name = ValueForKey (b->owner, "classname");
  581.     glRasterPos2f (b->mins[0]+4, b->mins[1]+4);
  582.     glCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
  583. }
  584.  
  585. /*
  586. =================
  587. MakeFaceWinding
  588.  
  589. returns the visible polygon on a face
  590. =================
  591. */
  592. winding_t    *MakeFaceWinding (brush_t *b, face_t *face)
  593. {
  594.     winding_t    *w;
  595.     face_t        *clip;
  596.     plane_t            plane;
  597.     qboolean        past;
  598.  
  599.     // get a poly that covers an effectively infinite area
  600.     w = BasePolyForPlane (&face->plane);
  601.  
  602.     // chop the poly by all of the other faces
  603.     past = false;
  604.     for (clip = b->brush_faces ; clip && w ; clip=clip->next)
  605.     {
  606.         if (clip == face)
  607.         {
  608.             past = true;
  609.             continue;
  610.         }
  611.         if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
  612.             && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
  613.         {    // identical plane, use the later one
  614.             if (past)
  615.             {
  616.                 free (w);
  617.                 return NULL;
  618.             }
  619.             continue;
  620.         }
  621.  
  622.         // flip the plane, because we want to keep the back side
  623.         VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
  624.         plane.dist = -clip->plane.dist;
  625.         
  626.         w = ClipWinding (w, &plane, false);
  627.         if (!w)
  628.             return w;
  629.     }
  630.     
  631.     if (w->numpoints < 3)
  632.     {
  633.         free(w);
  634.         w = NULL;
  635.     }
  636.  
  637.     if (!w)
  638.         printf ("unused plane\n");
  639.  
  640.     return w;
  641. }
  642.  
  643.  
  644. void Brush_SnapPlanepts (brush_t *b)
  645. {
  646.     int        i, j;
  647.     face_t    *f;
  648.  
  649.     for (f=b->brush_faces ; f; f=f->next)
  650.         for (i=0 ; i<3 ; i++)
  651.             for (j=0 ; j<3 ; j++)
  652.                 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
  653. }
  654.     
  655. /*
  656. ** Brush_Build
  657. **
  658. ** Builds a brush rendering data and also sets the min/max bounds
  659. */
  660. #define    ZERO_EPSILON    0.001
  661. void Brush_Build( brush_t *b )
  662. {
  663. //    int                order;
  664. //    face_t            *face;
  665. //    winding_t        *w;
  666.     char            title[1024];
  667.  
  668.     if (modified != 1)
  669.     {
  670.         modified = true;    // mark the map as changed
  671.         sprintf (title, "%s *", currentmap);
  672.  
  673.         QE_ConvertDOSToUnixName( title, title );
  674.         Sys_SetTitle (title);
  675.     }
  676.  
  677.     /*
  678.     ** build the windings and generate the bounding box
  679.     */
  680.     Brush_BuildWindings( b );
  681.  
  682.     /*
  683.     ** move the points and edges if in select mode
  684.     */
  685.     if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
  686.         SetupVertexSelection ();
  687. }
  688.  
  689. /*
  690. =================
  691. Brush_Parse
  692.  
  693. The brush is NOT linked to any list
  694. =================
  695. */
  696. brush_t *Brush_Parse (void)
  697. {
  698.     brush_t        *b;
  699.     face_t        *f;
  700.     int            i,j;
  701.  
  702.     g_qeglobals.d_parsed_brushes++;
  703.     b = qmalloc(sizeof(brush_t));
  704.         
  705.     do
  706.     {
  707.         if (!GetToken (true))
  708.             break;
  709.         if (!strcmp (token, "}") )
  710.             break;
  711.         
  712.         f = Face_Alloc();
  713.  
  714.         // add the brush to the end of the chain, so
  715.         // loading and saving a map doesn't reverse the order
  716.  
  717.         f->next = NULL;
  718.         if (!b->brush_faces)
  719.         {
  720.             b->brush_faces = f;
  721.         }
  722.         else
  723.         {
  724.             face_t *scan;
  725.  
  726.             for (scan=b->brush_faces ; scan->next ; scan=scan->next)
  727.                 ;
  728.             scan->next = f;
  729.         }
  730.  
  731.         // read the three point plane definition
  732.         for (i=0 ; i<3 ; i++)
  733.         {
  734.             if (i != 0)
  735.                 GetToken (true);
  736.             if (strcmp (token, "(") )
  737.                 Error ("parsing brush");
  738.             
  739.             for (j=0 ; j<3 ; j++)
  740.             {
  741.                 GetToken (false);
  742.                 f->planepts[i][j] = atoi(token);
  743.             }
  744.             
  745.             GetToken (false);
  746.             if (strcmp (token, ")") )
  747.                 Error ("parsing brush");
  748.                 
  749.         }
  750.  
  751.     // read the texturedef
  752.         GetToken (false);
  753.         strcpy(f->texdef.name, token);
  754.         GetToken (false);
  755.         f->texdef.shift[0] = atoi(token);
  756.         GetToken (false);
  757.         f->texdef.shift[1] = atoi(token);
  758.         GetToken (false);
  759.         f->texdef.rotate = atoi(token);    
  760.         GetToken (false);
  761.         f->texdef.scale[0] = atof(token);
  762.         GetToken (false);
  763.         f->texdef.scale[1] = atof(token);
  764.  
  765.         // the flags and value field aren't necessarily present
  766.         f->d_texture = Texture_ForName( f->texdef.name );
  767.         f->texdef.flags = f->d_texture->flags;
  768.         f->texdef.value = f->d_texture->value;
  769.         f->texdef.contents = f->d_texture->contents;
  770.  
  771.         if (TokenAvailable ())
  772.         {
  773.             GetToken (false);
  774.             f->texdef.contents = atoi(token);
  775.             GetToken (false);
  776.             f->texdef.flags = atoi(token);
  777.             GetToken (false);
  778.             f->texdef.value = atoi(token);
  779.         }
  780.     } while (1);
  781.  
  782.     return b;
  783. }
  784.  
  785. /*
  786. =================
  787. Brush_Write
  788. =================
  789. */
  790. void Brush_Write (brush_t *b, FILE *f)
  791. {
  792.     face_t    *fa;
  793.     char *pname;
  794.     int        i;
  795.  
  796.     fprintf (f, "{\n");
  797.     for (fa=b->brush_faces ; fa ; fa=fa->next)
  798.     {
  799.         for (i=0 ; i<3 ; i++)
  800.             fprintf (f, "( %i %i %i ) ", (int)fa->planepts[i][0]
  801.             , (int)fa->planepts[i][1], (int)fa->planepts[i][2]);
  802.  
  803.         pname = fa->texdef.name;
  804.         if (pname[0] == 0)
  805.             pname = "unnamed";
  806.  
  807.         fprintf (f, "%s %i %i %i ", pname,
  808.             (int)fa->texdef.shift[0], (int)fa->texdef.shift[1],
  809.             (int)fa->texdef.rotate);
  810.  
  811.         if (fa->texdef.scale[0] == (int)fa->texdef.scale[0])
  812.             fprintf (f, "%i ", (int)fa->texdef.scale[0]);
  813.         else
  814.             fprintf (f, "%f ", (float)fa->texdef.scale[0]);
  815.         if (fa->texdef.scale[1] == (int)fa->texdef.scale[1])
  816.             fprintf (f, "%i", (int)fa->texdef.scale[1]);
  817.         else
  818.             fprintf (f, "%f", (float)fa->texdef.scale[1]);
  819.  
  820.         // only output flags and value if not default
  821.         if (fa->texdef.value != fa->d_texture->value
  822.             || fa->texdef.flags != fa->d_texture->flags
  823.             || fa->texdef.contents != fa->d_texture->contents)
  824.         {
  825.             fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
  826.         }
  827.  
  828.         fprintf (f, "\n");
  829.     }
  830.     fprintf (f, "}\n");
  831. }
  832.  
  833.  
  834. /*
  835. =============
  836. Brush_Create
  837.  
  838. Create non-textured blocks for entities
  839. The brush is NOT linked to any list
  840. =============
  841. */
  842. brush_t    *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
  843. {
  844.     int        i, j;
  845.     vec3_t    pts[4][2];
  846.     face_t    *f;
  847.     brush_t    *b;
  848.  
  849.     for (i=0 ; i<3 ; i++)
  850.         if (maxs[i] < mins[i])
  851.             Error ("Brush_InitSolid: backwards");
  852.  
  853.     b = qmalloc (sizeof(brush_t));
  854.     
  855.     pts[0][0][0] = mins[0];
  856.     pts[0][0][1] = mins[1];
  857.     
  858.     pts[1][0][0] = mins[0];
  859.     pts[1][0][1] = maxs[1];
  860.     
  861.     pts[2][0][0] = maxs[0];
  862.     pts[2][0][1] = maxs[1];
  863.     
  864.     pts[3][0][0] = maxs[0];
  865.     pts[3][0][1] = mins[1];
  866.     
  867.     for (i=0 ; i<4 ; i++)
  868.     {
  869.         pts[i][0][2] = mins[2];
  870.         pts[i][1][0] = pts[i][0][0];
  871.         pts[i][1][1] = pts[i][0][1];
  872.         pts[i][1][2] = maxs[2];
  873.     }
  874.     
  875.     for (i=0 ; i<4 ; i++)
  876.     {
  877.         f = Face_Alloc();
  878.         f->texdef = *texdef;
  879.         f->next = b->brush_faces;
  880.         b->brush_faces = f;
  881.         j = (i+1)%4;
  882.  
  883.         VectorCopy (pts[j][1], f->planepts[0]);
  884.         VectorCopy (pts[i][1], f->planepts[1]);
  885.         VectorCopy (pts[i][0], f->planepts[2]);
  886.     }
  887.     
  888.     f = Face_Alloc();
  889.     f->texdef = *texdef;
  890.     f->next = b->brush_faces;
  891.     b->brush_faces = f;
  892.  
  893.     VectorCopy (pts[0][1], f->planepts[0]);
  894.     VectorCopy (pts[1][1], f->planepts[1]);
  895.     VectorCopy (pts[2][1], f->planepts[2]);
  896.  
  897.     f = Face_Alloc();
  898.     f->texdef = *texdef;
  899.     f->next = b->brush_faces;
  900.     b->brush_faces = f;
  901.  
  902.     VectorCopy (pts[2][0], f->planepts[0]);
  903.     VectorCopy (pts[1][0], f->planepts[1]);
  904.     VectorCopy (pts[0][0], f->planepts[2]);
  905.  
  906.     return b;
  907. }
  908.  
  909.  
  910. /*
  911. =============
  912. Brush_MakeSided
  913.  
  914. Makes the current brushhave the given number of 2d sides
  915. =============
  916. */
  917. void Brush_MakeSided (int sides)
  918. {
  919.     int        i;
  920.     vec3_t    mins, maxs;
  921.     brush_t    *b;
  922.     texdef_t    *texdef;
  923.     face_t    *f;
  924.     vec3_t    mid;
  925.     float    width;
  926.     float    sv, cv;
  927.  
  928.     if (sides < 3)
  929.     {
  930.         Sys_Status ("Bad sides number", 0);
  931.         return;
  932.     }
  933.  
  934.     if (!QE_SingleBrush ())
  935.     {
  936.         Sys_Status ("Must have a single brush selected", 0 );
  937.         return;
  938.     }
  939.  
  940.     b = selected_brushes.next;
  941.     VectorCopy (b->mins, mins);
  942.     VectorCopy (b->maxs, maxs);
  943.     texdef = &g_qeglobals.d_texturewin.texdef;
  944.  
  945.     Brush_Free (b);
  946.  
  947.     // find center of brush
  948.     width = 8;
  949.     for (i=0 ; i<2 ; i++)
  950.     {
  951.         mid[i] = (maxs[i] + mins[i])*0.5;
  952.         if (maxs[i] - mins[i] > width)
  953.             width = maxs[i] - mins[i];
  954.     }
  955.     width /= 2;
  956.  
  957.     b = qmalloc (sizeof(brush_t));
  958.         
  959.     // create top face
  960.     f = Face_Alloc();
  961.     f->texdef = *texdef;
  962.     f->next = b->brush_faces;
  963.     b->brush_faces = f;
  964.  
  965. f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2];
  966. f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2];
  967. f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2];
  968.  
  969.     // create bottom face
  970.     f = Face_Alloc();
  971.     f->texdef = *texdef;
  972.     f->next = b->brush_faces;
  973.     b->brush_faces = f;
  974.  
  975. f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
  976. f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
  977. f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
  978.  
  979.     for (i=0 ; i<sides ; i++)
  980.     {
  981.         f = Face_Alloc();
  982.         f->texdef = *texdef;
  983.         f->next = b->brush_faces;
  984.         b->brush_faces = f;
  985.  
  986.         sv = sin (i*3.14159265*2/sides);
  987.         cv = cos (i*3.14159265*2/sides);
  988.  
  989.         f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
  990.         f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
  991.         f->planepts[0][2] = mins[2];
  992.  
  993.         f->planepts[1][0] = f->planepts[0][0];
  994.         f->planepts[1][1] = f->planepts[0][1];
  995.         f->planepts[1][2] = maxs[2];
  996.  
  997.         f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5);
  998.         f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5);
  999.         f->planepts[2][2] = maxs[2];
  1000.  
  1001.     }
  1002.  
  1003.     Brush_AddToList (b, &selected_brushes);
  1004.  
  1005.     Entity_LinkBrush (world_entity, b);
  1006.  
  1007.     Brush_Build( b );
  1008.  
  1009.     Sys_UpdateWindows (W_ALL);
  1010. }
  1011.  
  1012.  
  1013. /*
  1014. =============
  1015. Brush_Free
  1016.  
  1017. Frees the brush with all of its faces and display list.
  1018. Unlinks the brush from whichever chain it is in.
  1019. Decrements the owner entity's brushcount.
  1020. Removes owner entity if this was the last brush
  1021. unless owner is the world.
  1022. =============
  1023. */
  1024. void Brush_Free (brush_t *b)
  1025. {
  1026.     face_t    *f, *next;
  1027.  
  1028.     // free faces
  1029.     for (f=b->brush_faces ; f ; f=next)
  1030.     {
  1031.         next = f->next;
  1032.         Face_Free( f );
  1033.     }
  1034.  
  1035.     /*
  1036.     for ( i = 0; i < b->d_numwindings; i++ )
  1037.     {
  1038.         if ( b->d_windings[i] )
  1039.         {
  1040.             FreeWinding( b->d_windings[i] );
  1041.             b->d_windings[i] = 0;
  1042.         }
  1043.     }
  1044.     */
  1045.  
  1046.     // unlink from active/selected list
  1047.     if (b->next)
  1048.         Brush_RemoveFromList (b);
  1049.  
  1050.     // unlink from entity list
  1051.     if (b->onext)
  1052.         Entity_UnlinkBrush (b);
  1053.  
  1054.     free (b);
  1055. }
  1056.  
  1057. /*
  1058. ============
  1059. Brush_Move
  1060. ============
  1061. */
  1062. void Brush_Move (brush_t *b, vec3_t move)
  1063. {
  1064.     int        i;
  1065.     face_t    *f;
  1066.  
  1067.     for (f=b->brush_faces ; f ; f=f->next)
  1068.         for (i=0 ; i<3 ; i++)
  1069.             VectorAdd (f->planepts[i], move, f->planepts[i]);
  1070.     Brush_Build( b );
  1071. }
  1072.  
  1073. /*
  1074. ============
  1075. Brush_Clone
  1076.  
  1077. Does NOT add the new brush to any lists
  1078. ============
  1079. */
  1080. brush_t *Brush_Clone (brush_t *b)
  1081. {
  1082.     brush_t    *n;
  1083.     face_t    *f, *nf;
  1084.  
  1085.     n = qmalloc(sizeof(brush_t));
  1086.     n->owner = b->owner;
  1087.     for (f=b->brush_faces ; f ; f=f->next)
  1088.     {
  1089.         nf = Face_Clone( f );
  1090.         nf->next = n->brush_faces;
  1091.         n->brush_faces = nf;
  1092.     }
  1093.     return n;
  1094. }
  1095.  
  1096. /*
  1097. ==============
  1098. Brush_Ray
  1099.  
  1100. Itersects a ray with a brush
  1101. Returns the face hit and the distance along the ray the intersection occured at
  1102. Returns NULL and 0 if not hit at all
  1103. ==============
  1104. */
  1105. face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist)
  1106. {
  1107.     face_t    *f, *firstface;
  1108.     vec3_t    p1, p2;
  1109.     float    frac, d1, d2;
  1110.     int        i;
  1111.  
  1112.     VectorCopy (origin, p1);
  1113.     for (i=0 ; i<3 ; i++)
  1114.         p2[i] = p1[i] + dir[i]*16384;
  1115.  
  1116.     for (f=b->brush_faces ; f ; f=f->next)
  1117.     {
  1118.         d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
  1119.         d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
  1120.         if (d1 >= 0 && d2 >= 0)
  1121.         {
  1122.             *dist = 0;
  1123.             return NULL;    // ray is on front side of face
  1124.         }
  1125.         if (d1 <=0 && d2 <= 0)
  1126.             continue;
  1127.     // clip the ray to the plane
  1128.         frac = d1 / (d1 - d2);
  1129.         if (d1 > 0)
  1130.         {
  1131.             firstface = f;
  1132.             for (i=0 ; i<3 ; i++)
  1133.                 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
  1134.         }
  1135.         else
  1136.         {
  1137.             for (i=0 ; i<3 ; i++)
  1138.                 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
  1139.         }
  1140.     }
  1141.  
  1142.     // find distance p1 is along dir
  1143.     VectorSubtract (p1, origin, p1);
  1144.     d1 = DotProduct (p1, dir);
  1145.  
  1146.     *dist = d1;
  1147.  
  1148.     return firstface;
  1149. }
  1150.  
  1151. void    Brush_AddToList (brush_t *b, brush_t *list)
  1152. {
  1153.     if (b->next || b->prev)
  1154.         Error ("Brush_RemoveFromList: allready linked");
  1155.     b->next = list->next;
  1156.     list->next->prev = b;
  1157.     list->next = b;
  1158.     b->prev = list;
  1159. }
  1160.  
  1161. void    Brush_RemoveFromList (brush_t *b)
  1162. {
  1163.     if (!b->next || !b->prev)
  1164.         Error ("Brush_RemoveFromList: not linked");
  1165.     b->next->prev = b->prev;
  1166.     b->prev->next = b->next;
  1167.     b->next = b->prev = NULL;
  1168. }
  1169.  
  1170. void    Brush_SetTexture (brush_t *b, texdef_t *texdef)
  1171. {
  1172.     face_t    *f;
  1173.  
  1174.     for (f=b->brush_faces ; f ; f=f->next)
  1175.         f->texdef = *texdef;
  1176.     Brush_Build( b );
  1177. }
  1178.  
  1179.  
  1180. qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
  1181. {
  1182.     float    d1, d2, fr;
  1183.     int        i;
  1184.     float    *v;
  1185.  
  1186.     d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
  1187.     d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
  1188.  
  1189.     if (d1 >= 0 && d2 >= 0)
  1190.         return false;        // totally outside
  1191.     if (d1 <= 0 && d2 <= 0)
  1192.         return true;        // totally inside
  1193.  
  1194.     fr = d1 / (d1 - d2);
  1195.  
  1196.     if (d1 > 0)
  1197.         v = p1;
  1198.     else
  1199.         v = p2;
  1200.  
  1201.     for (i=0 ; i<3 ; i++)
  1202.         v[i] = p1[i] + fr*(p2[i] - p1[i]);
  1203.  
  1204.     return true;
  1205. }
  1206.  
  1207.  
  1208. int AddPlanept (float *f)
  1209. {
  1210.     int        i;
  1211.  
  1212.     for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
  1213.         if (g_qeglobals.d_move_points[i] == f)
  1214.             return 0;
  1215.     g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
  1216.     return 1;
  1217. }
  1218.  
  1219. /*
  1220. ==============
  1221. Brush_SelectFaceForDragging
  1222.  
  1223. Adds the faces planepts to move_points, and
  1224. rotates and adds the planepts of adjacent face if shear is set
  1225. ==============
  1226. */
  1227. void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
  1228. {
  1229.     int        i;
  1230.     face_t    *f2;
  1231.     winding_t    *w;
  1232.     float    d;
  1233.     brush_t    *b2;
  1234.     int        c;
  1235.  
  1236.     if (b->owner->eclass->fixedsize)
  1237.         return;
  1238.  
  1239.     c = 0;
  1240.     for (i=0 ; i<3 ; i++)
  1241.         c += AddPlanept (f->planepts[i]);
  1242.     if (c == 0)
  1243.         return;        // allready completely added
  1244.  
  1245.     // select all points on this plane in all brushes the selection
  1246.     for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
  1247.     {
  1248.         if (b2 == b)
  1249.             continue;
  1250.         for (f2=b2->brush_faces ; f2 ; f2=f2->next)
  1251.         {
  1252.             for (i=0 ; i<3 ; i++)
  1253.                 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
  1254.                 -f->plane.dist) > ON_EPSILON)
  1255.                     break;
  1256.             if (i==3)
  1257.             {    // move this face as well
  1258.                 Brush_SelectFaceForDragging (b2, f2, shear);
  1259.                 break;
  1260.             }
  1261.         }
  1262.     }
  1263.  
  1264.  
  1265.     // if shearing, take all the planes adjacent to 
  1266.     // selected faces and rotate their points so the
  1267.     // edge clipped by a selcted face has two of the points
  1268.     if (!shear)
  1269.         return;
  1270.  
  1271.     for (f2=b->brush_faces ; f2 ; f2=f2->next)
  1272.     {
  1273.         if (f2 == f)
  1274.             continue;
  1275.         w = MakeFaceWinding (b, f2);
  1276.         if (!w)
  1277.             continue;
  1278.  
  1279.         // any points on f will become new control points
  1280.         for (i=0 ; i<w->numpoints ; i++)
  1281.         {
  1282.             d = DotProduct (w->points[i], f->plane.normal) 
  1283.                 - f->plane.dist;
  1284.             if (d > -ON_EPSILON && d < ON_EPSILON)
  1285.                 break;
  1286.         }
  1287.  
  1288.         //
  1289.         // if none of the points were on the plane,
  1290.         // leave it alone
  1291.         //
  1292.         if (i != w->numpoints)
  1293.         {
  1294.             if (i == 0)
  1295.             {    // see if the first clockwise point was the
  1296.                 // last point on the winding
  1297.                 d = DotProduct (w->points[w->numpoints-1]
  1298.                     , f->plane.normal) - f->plane.dist;
  1299.                 if (d > -ON_EPSILON && d < ON_EPSILON)
  1300.                     i = w->numpoints - 1;
  1301.             }
  1302.  
  1303.             AddPlanept (f2->planepts[0]);
  1304.  
  1305.             VectorCopy (w->points[i], f2->planepts[0]);
  1306.             if (++i == w->numpoints)
  1307.                 i = 0;
  1308.             
  1309.             // see if the next point is also on the plane
  1310.             d = DotProduct (w->points[i]
  1311.                 , f->plane.normal) - f->plane.dist;
  1312.             if (d > -ON_EPSILON && d < ON_EPSILON)
  1313.                 AddPlanept (f2->planepts[1]);
  1314.  
  1315.             VectorCopy (w->points[i], f2->planepts[1]);
  1316.             if (++i == w->numpoints)
  1317.                 i = 0;
  1318.  
  1319.             // the third point is never on the plane
  1320.  
  1321.             VectorCopy (w->points[i], f2->planepts[2]);
  1322.         }
  1323.  
  1324.         free(w);
  1325.     }
  1326. }
  1327.  
  1328. /*
  1329. ==============
  1330. Brush_SideSelect
  1331.  
  1332. The mouse click did not hit the brush, so grab one or more side
  1333. planes for dragging
  1334. ==============
  1335. */
  1336. void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
  1337.                        , qboolean shear)
  1338. {
  1339.     face_t    *f, *f2;
  1340.     vec3_t    p1, p2;
  1341.  
  1342.     for (f=b->brush_faces ; f ; f=f->next)
  1343.     {
  1344.         VectorCopy (origin, p1);
  1345.         VectorMA (origin, 16384, dir, p2);
  1346.  
  1347.         for (f2=b->brush_faces ; f2 ; f2=f2->next)
  1348.         {
  1349.             if (f2 == f)
  1350.                 continue;
  1351.             ClipLineToFace (p1, p2, f2);
  1352.         }
  1353.  
  1354.         if (f2)
  1355.             continue;
  1356.  
  1357.         if (VectorCompare (p1, origin))
  1358.             continue;
  1359.         if (ClipLineToFace (p1, p2, f))
  1360.             continue;
  1361.  
  1362.         Brush_SelectFaceForDragging (b, f, shear);
  1363.     }
  1364.  
  1365.     
  1366. }
  1367.  
  1368. void Brush_BuildWindings( brush_t *b )
  1369. {
  1370.     winding_t *w;
  1371.     face_t    *face;
  1372.     vec_t      v;
  1373.  
  1374.     Brush_SnapPlanepts( b );
  1375.  
  1376.     // clear the mins/maxs bounds
  1377.     b->mins[0] = b->mins[1] = b->mins[2] = 99999;
  1378.     b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
  1379.  
  1380.     Brush_MakeFacePlanes (b);
  1381.  
  1382.     face = b->brush_faces;
  1383.  
  1384.     for ( ; face ; face=face->next)
  1385.     {
  1386.         int i, j;
  1387.  
  1388.         w = face->face_winding = MakeFaceWinding (b, face);
  1389.         face->d_texture = Texture_ForName( face->texdef.name );
  1390.  
  1391.         if (!w)
  1392.         {
  1393.             continue;
  1394.         }
  1395.     
  1396.         for (i=0 ; i<w->numpoints ; i++)
  1397.         {
  1398.             // add to bounding box
  1399.             for (j=0 ; j<3 ; j++)
  1400.             {
  1401.                 v = w->points[i][j];
  1402.                 if (v > b->maxs[j])
  1403.                     b->maxs[j] = v;
  1404.                 if (v < b->mins[j])
  1405.                     b->mins[j] = v;
  1406.             }
  1407.         }
  1408.         // setup s and t vectors, and set color
  1409.         BeginTexturingFace( b, face, face->d_texture);
  1410.  
  1411.  
  1412.         for (i=0 ; i<w->numpoints ; i++)
  1413.         {
  1414.             EmitTextureCoordinates( w->points[i], face->d_texture, face);
  1415.         }
  1416.     }
  1417. }
  1418.  
  1419. /*
  1420. ==================
  1421. Brush_RemoveEmptyFaces
  1422.  
  1423. Frees any overconstraining faces
  1424. ==================
  1425. */
  1426. void Brush_RemoveEmptyFaces ( brush_t *b )
  1427. {
  1428.     face_t    *f, *next;
  1429.  
  1430.     f = b->brush_faces;
  1431.     b->brush_faces = NULL;
  1432.  
  1433.     for ( ; f ; f=next)
  1434.     {
  1435.         next = f->next;
  1436.         if (!f->face_winding)
  1437.             Face_Free (f);
  1438.         else
  1439.         {
  1440.             f->next = b->brush_faces;
  1441.             b->brush_faces = f;
  1442.         }
  1443.  
  1444.     }
  1445. }
  1446.  
  1447. void Brush_Draw( brush_t *b )
  1448. {
  1449.     face_t            *face;
  1450.     int                i, order;
  1451.     qtexture_t        *prev = 0;
  1452.     winding_t *w;
  1453.  
  1454.     if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
  1455.         glDisable (GL_TEXTURE_2D);
  1456.  
  1457.     // guarantee the texture will be set first
  1458.     prev = NULL;
  1459.     for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
  1460.     {
  1461.         w = face->face_winding;
  1462.         if (!w)
  1463.             continue;        // freed face
  1464.  
  1465.         if ( face->d_texture != prev && camera.draw_mode == cd_texture)
  1466.         {
  1467.             // set the texture for this face
  1468.             prev = face->d_texture;
  1469.             glBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
  1470.         }
  1471.  
  1472.         glColor3fv( face->d_color );
  1473.  
  1474.         // draw the polygon
  1475.         glBegin(GL_POLYGON);
  1476.         for (i=0 ; i<w->numpoints ; i++)
  1477.         {
  1478.             if (camera.draw_mode == cd_texture)
  1479.                 glTexCoord2fv( &w->points[i][3] );
  1480.             glVertex3fv(w->points[i]);
  1481.         }
  1482.         glEnd();
  1483.     }
  1484.  
  1485.     if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
  1486.         glEnable (GL_TEXTURE_2D);
  1487.  
  1488.     glBindTexture( GL_TEXTURE_2D, 0 );
  1489. }
  1490.  
  1491. void Face_Draw( face_t *f )
  1492. {
  1493.     int i;
  1494.  
  1495.     if ( f->face_winding == 0 )
  1496.         return;
  1497.     glBegin( GL_POLYGON );
  1498.     for ( i = 0 ; i < f->face_winding->numpoints; i++)
  1499.         glVertex3fv( f->face_winding->points[i] );
  1500.     glEnd();
  1501. }
  1502.  
  1503. void Brush_DrawXY( brush_t *b )
  1504. {
  1505.     face_t *face;
  1506.     int     order;
  1507.     winding_t *w;
  1508.     int        i;
  1509.  
  1510.     for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
  1511.     {
  1512.         // only draw up facing polygons
  1513.         if (face->plane.normal[2] <= 0)
  1514.             continue;
  1515.  
  1516.         w = face->face_winding;
  1517.         if (!w)
  1518.             continue;
  1519.  
  1520.         // draw the polygon
  1521.         glBegin(GL_LINE_LOOP);
  1522.         for (i=0 ; i<w->numpoints ; i++)
  1523.             glVertex3fv(w->points[i]);
  1524.         glEnd();
  1525.     }
  1526.  
  1527.     // optionally add a text label
  1528.     if ( g_qeglobals.d_savedinfo.show_names )
  1529.         DrawBrushEntityName (b);
  1530. }
  1531.  
  1532. face_t *Face_Alloc( void )
  1533. {
  1534.     face_t *f = qmalloc( sizeof( *f ) );
  1535.  
  1536.     return f;
  1537. }
  1538.  
  1539. void Face_Free( face_t *f )
  1540. {
  1541.     assert( f != 0 );
  1542.  
  1543.     if ( f->face_winding )
  1544.         free( f->face_winding ), f->face_winding = 0;
  1545.     free( f );
  1546. }
  1547.